import { Client } from "./mod.ts";
import { Repository } from "./repo.ts";
import { User } from "./user.ts";
import { Issue, Comment } from "./issue.ts";
import { PayloadUser, PayloadCommit } from "./repo_branch.ts";
import { PullRequest } from "./pull.ts";
import { Release } from "./release.ts";

/**
 * Hook represents a webhook.
 */
export interface Hook {
  id: number;
  type: string;
  config: Record<string, string>;
  events: string[];
  active: boolean;
  updated_at: string;
  created_at: string;
}

/**
 * CreateHookOption represents options for creating a webhook
 */
export interface CreateHookOption {
  type: string;
  config: Record<string, string>;
  events?: string[];
  active?: boolean;
}

/**
 * EditHookOption represents options for editing a webhook
 */
export interface EditHookOption {
  config?: Record<string, string>;
  events?: string[];
  active?: boolean;
}

/**
 * Interface for all webhook payloads
 */
export interface Payloader {
  jsonPayload(): Promise<string>;
}

/**
 * Create payload for webhook
 */
export interface CreatePayload {
  ref: string;
  ref_type: string;
  sha: string;
  default_branch: string;
  repository: Repository;
  sender: User;
}

/**
 * Pusher type
 */
export type PusherType = "user";

/**
 * Delete payload for webhook
 */
export interface DeletePayload {
  ref: string;
  ref_type: string;
  pusher_type: PusherType;
  repository: Repository;
  sender: User;
}

/**
 * Fork payload for webhook
 */
export interface ForkPayload {
  forkee: Repository;
  repository: Repository;
  sender: User;
}

/**
 * Push payload for webhook
 */
export interface PushPayload {
  ref: string;
  before: string;
  after: string;
  compare_url: string;
  commits: PayloadCommit[];
  repository: Repository;
  pusher: User;
  sender: User;
}

/**
 * Issue action type
 */
export type HookIssueAction = 
  | "opened" 
  | "closed" 
  | "reopened" 
  | "edited" 
  | "assigned" 
  | "unassigned" 
  | "label_updated" 
  | "label_cleared" 
  | "milestoned" 
  | "demilestoned" 
  | "synchronized";

/**
 * Change from payload
 */
export interface ChangesFromPayload {
  from: string;
}

/**
 * Changes payload
 */
export interface ChangesPayload {
  title?: ChangesFromPayload;
  body?: ChangesFromPayload;
}

/**
 * Issue payload for webhook
 */
export interface IssuesPayload {
  action: HookIssueAction;
  number: number;
  issue: Issue;
  changes?: ChangesPayload;
  repository: Repository;
  sender: User;
}

/**
 * Hook issue comment action type
 */
export type HookIssueCommentAction = 
  | "created" 
  | "edited" 
  | "deleted";

/**
 * Issue comment payload for webhook
 */
export interface IssueCommentPayload {
  action: HookIssueCommentAction;
  issue: Issue;
  comment: Comment;
  repository: Repository;
  sender: User;
}

/**
 * Pull request payload for webhook
 */
export interface PullRequestPayload {
  action: HookIssueAction;
  number: number;
  pull_request: PullRequest;
  repository: Repository;
  sender: User;
}

/**
 * Hook release action type
 */
export type HookReleaseAction = 
  | "published" 
  | "updated" 
  | "deleted";

/**
 * Release payload for webhook
 */
export interface ReleasePayload {
  action: HookReleaseAction;
  release: Release;
  repository: Repository;
  sender: User;
}

/**
 * Hook API endpoints
 */
export class HookAPI {
  constructor(private client: Client) {}

  /**
   * List webhooks of a repository
   */
  async listRepoHooks(owner: string, repo: string): Promise<Hook[]> {
    return await this.client.doRequest<Hook[]>(
      "GET", 
      `/repos/${owner}/${repo}/hooks`
    );
  }

  /**
   * Create a webhook for a repository
   */
  async createRepoHook(owner: string, repo: string, options: CreateHookOption): Promise<Hook> {
    return await this.client.doRequest<Hook>(
      "POST", 
      `/repos/${owner}/${repo}/hooks`, 
      { "Content-Type": "application/json" },
      options
    );
  }

  /**
   * Edit a webhook of a repository
   */
  async editRepoHook(owner: string, repo: string, id: number, options: EditHookOption): Promise<void> {
    await this.client.doRequest<void>(
      "PATCH", 
      `/repos/${owner}/${repo}/hooks/${id}`, 
      { "Content-Type": "application/json" },
      options
    );
  }

  /**
   * Delete a webhook from a repository
   */
  async deleteRepoHook(owner: string, repo: string, id: number): Promise<void> {
    await this.client.doRequest<void>(
      "DELETE", 
      `/repos/${owner}/${repo}/hooks/${id}`
    );
  }
} 